Skip to content

feat: add recent search history for tracked GitHub profiles#660

Open
PalashKulkarni wants to merge 1 commit into
GitMetricsLab:mainfrom
PalashKulkarni:feat/recent-search-history
Open

feat: add recent search history for tracked GitHub profiles#660
PalashKulkarni wants to merge 1 commit into
GitMetricsLab:mainfrom
PalashKulkarni:feat/recent-search-history

Conversation

@PalashKulkarni
Copy link
Copy Markdown

@PalashKulkarni PalashKulkarni commented Jun 1, 2026

Related Issue


Description

This PR adds a Recent Search History feature to the Tracker page, allowing users to quickly revisit previously searched GitHub profiles.

Changes Made

  • Added persistent recent search history using localStorage
  • Stores up to 10 recently searched GitHub usernames
  • Prevents duplicate entries by moving existing usernames to the top
  • Automatically loads saved history on page refresh
  • Added clickable recent search items for one-click profile tracking
  • Added a Clear History button to remove all stored searches
  • Trimmed usernames and ignored empty inputs before processing
  • Updated the search flow to save usernames only after a successful data fetch

Benefits

  • Improves user experience by reducing repetitive typing
  • Makes it easier to revisit frequently tracked GitHub profiles
  • Requires no backend changes
  • Integrates seamlessly with the existing Tracker workflow

How Has This Been Tested?

  • Verified recent searches are stored in localStorage
  • Verified history persists across page refreshes
  • Verified duplicate usernames are moved to the top instead of being duplicated
  • Verified empty and whitespace-only usernames are ignored
  • Verified clicking a recent search automatically triggers the existing search flow
  • Verified the Clear History button removes all stored entries immediately
  • Verified usernames are saved only after successful GitHub data retrieval

Screenshots (if applicable)

N/A – This feature primarily adds functionality and persistence behavior. UI changes are minimal and integrated into the existing Tracker page.


Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

  • New Features
    • Introduced "Recent Searches" panel displaying your previously searched usernames for convenient quick re-access to recent lookups
    • Added "Clear History" button to remove and manage stored search history
    • Search history automatically persists across browser sessions for continued access

@netlify
Copy link
Copy Markdown

netlify Bot commented Jun 1, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 4983818
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a1d1dd62fbc6100084f927b
😎 Deploy Preview https://deploy-preview-660--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a recent search history feature to the GitHub Tracker. The hook fetchData now returns a boolean indicating fetch success/failure instead of void. Tracker then uses this signal to persist recently searched usernames to localStorage, displaying them in a UI panel for quick re-access with automatic history clearing.

Changes

Recent Search History Feature

Layer / File(s) Summary
fetchData return type and success/stale signaling
src/hooks/useGitHubData.ts
fetchData now returns Promise<boolean>: false for missing Octokit, blank username, rate-limiting, stale requests, or API rejections; true only when all paginated requests succeed.
Recent search persistence, initialization, and handlers
src/pages/Tracker/Tracker.tsx
Tracker adds localStorage constants, recentSearches state, helpers to normalize/load/add/clear searches, initial hydration from storage, async handleSubmit and recent-search click handlers that normalize input, reset pagination, invoke fetchData, and append to history only on successful fetch.
Recent searches UI panel
src/pages/Tracker/Tracker.tsx
Tracker renders a Recent Searches section above the main content with a Clear History button and small outlined buttons for each stored recent search, each triggering the recent-search click handler.

Sequence Diagram

sequenceDiagram
  participant User
  participant Tracker
  participant useGitHubData
  participant localStorage

  User->>Tracker: Enter username or click recent search
  Tracker->>Tracker: Normalize username, reset page
  Tracker->>useGitHubData: Call fetchData(username)
  useGitHubData->>useGitHubData: Validate Octokit, check rate limit
  useGitHubData->>useGitHubData: Fetch issues/PRs via GitHub API
  useGitHubData->>Tracker: Return true (success) or false (failure)
  alt Fetch successful
    Tracker->>localStorage: Save username to recent searches
  end
  Tracker->>localStorage: Load recent searches on mount
  User->>Tracker: Click recent search button
  Tracker->>Tracker: Trigger fetch with stored username
  Tracker->>User: Display results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • GitMetricsLab/github_tracker#149: Modifies fetchData in useGitHubData.ts to use paginated concurrent fetching with total counts—directly overlaps with the main PR's return-type changes in the same hook.
  • GitMetricsLab/github_tracker#517: Modifies Tracker.tsx data-fetch trigger logic to switch from manual submit to effect-driven fetching and change when state like username/tab/page causes requests.
  • GitMetricsLab/github_tracker#298: Modifies useGitHubData.ts catch-block error/validation messaging logic for tracker fetches—intersects with the main PR's boolean return semantics and stale handling.

Suggested labels

type:feature, level:intermediate, quality:clean

Poem

🐰 Through recent searches, a rabbit hops fast,
No more typing the same paths in the past!
Boolean returns guide when to save and when not,
LocalStorage keeps history—what a fine plot! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly reflects the main feature being added: a recent search history system for GitHub profile tracking.
Description check ✅ Passed The description follows the template structure with all required sections completed, including related issue, detailed description, testing methodology, type of change, and appropriate reasoning for N/A screenshots.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #659: localStorage persistence, 10-item limit, duplicate prevention, clickable history, Clear History button, empty input handling, and successful-fetch-only saving.
Out of Scope Changes check ✅ Passed The PR focuses solely on adding recent search history functionality. The hook API change supports this feature and is not extraneous.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PalashKulkarni
Copy link
Copy Markdown
Author

Hi maintainers 👋

I've submitted a PR for Issue #659 that adds a Recent Search History feature to the Tracker page.

What was implemented:

  • Persistent recent searches using localStorage
  • Stores up to 10 GitHub usernames
  • Prevents duplicate entries by moving existing searches to the top
  • One-click re-search functionality
  • Clear History option
  • Saves usernames only after successful data retrieval

I've tested the feature locally and ensured it integrates with the existing search workflow without requiring backend changes.

I would appreciate it if you could review the PR and merge it if everything looks good. I'm happy to make any requested changes or improvements.

Thank you for your time and feedback! 🚀

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hooks/useGitHubData.ts (1)

143-189: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve error classification/rate-limit gating for per-request failures in Promise.allSettled

In src/hooks/useGitHubData.ts (around lines 143-189), Promise.allSettled(requests) prevents individual request rejections from reaching the outer catch where 403/rate-limit and other specific errors are classified; instead the code only sets the generic partial-failure message and then unconditionally calls setRateLimited(false).

Possible fix
+      const applyFetchError = (err: { status?: number; message?: string }) => {
+        const errorMessage = err.message?.toLowerCase() || '';
+
+        if (err.status === 403) {
+          setError(
+            'GitHub API rate limit exceeded. Please provide a PAT to continue.'
+          );
+          setRateLimited(true);
+        } else if (errorMessage.includes('do not exist')) {
+          setError('User not found. Please check the GitHub username.');
+        } else if (errorMessage.includes('validation failed')) {
+          setError('Invalid GitHub username or insufficient permissions.');
+        } else if (err.status === 401 || errorMessage.includes('permission')) {
+          setError('Private repository detected. Please provide a PAT.');
+        } else if (err.status === 404) {
+          setError('Resource not found.');
+        } else {
+          setError(
+            'Unable to fetch GitHub data. Please verify the username, token, or network connection.'
+          );
+        }
+      };
+
       const results = await Promise.allSettled(requests);
@@
-        const hasRejected = results.some(
-          (result) => result.status === 'rejected'
-        );
-
-        if (hasRejected) {
-          setError(
-            'Some GitHub data could not be fetched completely.'
-          );
-        }
+        const rejected = results.find(
+          (result): result is PromiseRejectedResult =>
+            result.status === 'rejected'
+        );
+
+        if (rejected) {
+          applyFetchError(rejected.reason as {
+            status?: number;
+            message?: string;
+          });
+          return false;
+        }
 
         setRateLimited(false);
-        return !hasRejected;
+        return true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useGitHubData.ts` around lines 143 - 189,
Promise.allSettled(requests) swallows per-request errors, so restore error
classification by inspecting rejected results and either rethrowing or handling
rate-limit specifically. After computing results and before calling
setRateLimited(false), scan results for rejected entries; if any rejection’s
reason indicates 403/rate-limit, trigger the existing path by throwing that
error so the outer catch classifies it (and sets setRateLimited(true)),
otherwise setError with the generic partial-failure message. Only call
setRateLimited(false) when all requests are fulfilled; do not reset it to false
if any rejection occurred. Use existing symbols: Promise.allSettled(requests),
setError, setRateLimited, shouldFetchIssues/shouldFetchPrs, setIssues/setPrs
setters to locate the block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/Tracker/Tracker.tsx`:
- Around line 147-151: The duplicate fetches are caused by calling fetchData
inside handleSubmit/handleRecentSearchClick while also relying on the
useEffect([tab, page]) to fetch; fix by moving fetch control entirely into the
effect: add username to the useEffect dependency array (useEffect(() => { if
(username) fetchData(username, page + 1, ROWS_PER_PAGE); }, [tab, page,
username])) and remove the immediate await fetchData(...) calls from
handleSubmit and handleRecentSearchClick (keep their setUsername and setPage(0)
calls so the effect drives the fetch). This consolidates fetch logic into
useEffect and prevents double requests.

---

Outside diff comments:
In `@src/hooks/useGitHubData.ts`:
- Around line 143-189: Promise.allSettled(requests) swallows per-request errors,
so restore error classification by inspecting rejected results and either
rethrowing or handling rate-limit specifically. After computing results and
before calling setRateLimited(false), scan results for rejected entries; if any
rejection’s reason indicates 403/rate-limit, trigger the existing path by
throwing that error so the outer catch classifies it (and sets
setRateLimited(true)), otherwise setError with the generic partial-failure
message. Only call setRateLimited(false) when all requests are fulfilled; do not
reset it to false if any rejection occurred. Use existing symbols:
Promise.allSettled(requests), setError, setRateLimited,
shouldFetchIssues/shouldFetchPrs, setIssues/setPrs setters to locate the block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de33127e-7426-4b90-8460-e87822269448

📥 Commits

Reviewing files that changed from the base of the PR and between 53f820b and 4983818.

📒 Files selected for processing (2)
  • src/hooks/useGitHubData.ts
  • src/pages/Tracker/Tracker.tsx

Comment on lines 147 to 151
useEffect(() => {
if (username) {
fetchData(username, page + 1, ROWS_PER_PAGE);
}
}, [tab, page]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '147,197p' src/pages/Tracker/Tracker.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 1165


Duplicate API calls when searching from non-zero pages

Both handleSubmit and handleRecentSearchClick call setPage(0) then immediately await fetchData(..., 1, ...). Setting page to 0 triggers the [tab, page] effect, which fetches the same page 1 data again. This wastes GitHub API quota on every search initiated from pages beyond the first.

Move all fetch logic into the effect, or add a flag to prevent the effect from running when handlers have already fetched.

Affected code
useEffect(() => {
  if (username) {
    fetchData(username, page + 1, ROWS_PER_PAGE);
  }
}, [tab, page]);

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
  // ...
  setUsername(normalizedUsername);
  setPage(0);

  const wasSuccessful = await fetchData(
    normalizedUsername,
    1,
    ROWS_PER_PAGE
  );
  // ...
};

const handleRecentSearchClick = async (value: string) => {
  // ...
  setUsername(normalizedUsername);
  setPage(0);

  const wasSuccessful = await fetchData(
    normalizedUsername,
    1,
    ROWS_PER_PAGE
  );
  // ...
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 147 - 151, The duplicate fetches
are caused by calling fetchData inside handleSubmit/handleRecentSearchClick
while also relying on the useEffect([tab, page]) to fetch; fix by moving fetch
control entirely into the effect: add username to the useEffect dependency array
(useEffect(() => { if (username) fetchData(username, page + 1, ROWS_PER_PAGE);
}, [tab, page, username])) and remove the immediate await fetchData(...) calls
from handleSubmit and handleRecentSearchClick (keep their setUsername and
setPage(0) calls so the effect drives the fetch). This consolidates fetch logic
into useEffect and prevents double requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add Recent Search History for Tracked GitHub Profiles

1 participant